import React, { FC, useEffect, useMemo, useRef, useState } from "react"
import QuestionCard from "../../components/QuestionCard"
import styles from "./common.module.scss"
import { useDebounceFn, useRequest, useTitle } from "ahooks"
import { Typography, Spin, Empty } from "antd"
import ListSearch from "../../components/ListSearch"
import { useSearchParams } from "react-router-dom"
import { getQuestionListService } from "../../services/question"
import { LIST_PAGE_SIZE, LIST_SEARCH_PARAM_KEY } from "../../constant"

const List: FC = () => {
    // 标题组件（组件库）
    const { Title } = Typography
    // 修改标题（使用第三方hook）
    useTitle("问卷星途 - 我的问卷")

    const [started, setStarted] = useState(false) // 是否开始加载数据（防抖，有延迟时间）
    const [page, setPage] = useState(1) // 当前页面，不在url中体现
    const [list, setList] = useState([]) // 累计当前数据（所有页面的数据累计和）,上滑加载更多
    const [total, setTotal] = useState(0) // 所有数据

    // 判断是否有更多未加载完成的数据
    const haveMoreData = total > list.length // 总数居大于当前加载的所有数据，true可以继续加载，false已经加载完毕

    // url参数中没有page和pageSize参数，但是又keyword
    const [searchParams] = useSearchParams()
    const keyword = searchParams.get(LIST_SEARCH_PARAM_KEY) || ""

    // 当keyword有变化重置所有的信息
    useEffect(() => {
        setStarted(false)
        setPage(1)
        setList([])
        setTotal(0)
    }, [keyword])

    // 真正的数据加载（手动执行）
    // run:load是解构中的重命名
    const { loading, run: load } = useRequest(
        async () => {
            const data = await getQuestionListService({
                page,
                pageSize: LIST_PAGE_SIZE,
                keyword
            })
            return data
        },
        {
            manual: true,
            //  回调函数会在异步请求(getQuestionListService)成功完成时被调用
            onSuccess(result) {
                // list重命名为l
                const { list: l = [], total = 0 } = result
                // list是累计，要进行拼接
                setList(list.concat(l))
                setTotal(total)
                setPage(page + 1) // 成功加载page就要+1
            }
        }
    )

    // 获取DOM节点
    const containerRef = useRef<HTMLDivElement>(null)
    // 尝试去触发加载 - 防抖(第三方hook)
    // run:tryLoadMore 重命名
    const { run: tryLoadMore } = useDebounceFn(
        () => {
            const elem = containerRef.current
            if (elem === null) return
            const domRect = elem.getBoundingClientRect()
            if (domRect === null) return
            const { bottom } = domRect // bottom就是该元素底部到页面顶部的距离
            if (bottom <= document.body.clientHeight) {
                // 如果bottom小于视口的高度，就表示该元素露出来了
                load() // 真正加载数据
                setStarted(true)
            }
        },
        {
            wait: 1000
        }
    )

    // 1、当页面加载或者url 参数（keyword）变化时，触发加载
    useEffect(() => {
        tryLoadMore() // 加载第一页数据，初始化操作
    }, [searchParams]) // 当搜索时要重新加载更多

    // 2、当页面滚动时，要尝试触发加载
    useEffect(() => {
        // 可以加载更多数据
        if (haveMoreData) {
            // 添加页面滑动监听事件
            window.addEventListener("scroll", tryLoadMore) // 添加防抖
        }
        return () => {
            // 移除滑动监听事件(解绑事件)
            window.removeEventListener("scroll", tryLoadMore)
        }
    }, [searchParams, haveMoreData]) // haveMoreData跟新要重新触发加载，因为刚开始可能为false

    // 加载更多逻辑实现
    const LoadMoreContentElem = useMemo(() => {
        // 没有开始或者加载中设置Spin
        if (!started || loading) return <Spin />
        if (total === 0) return <Empty description="暂无数据" />
        if (!haveMoreData) return <span>没有更多数据了...</span>
        return <span>加载中...</span>
    }, [started, loading, haveMoreData])

    return (
        <div>
            <div className={styles.header}>
                <div className={styles.left}>
                    {/* title渲染为h1 */}
                    <Title level={3}>我的问卷</Title>
                </div>
                <div className={styles.right}>
                    <ListSearch />
                </div>
            </div>
            <div className={styles.content}>
                {/* 不是加载状态就显示列表 */}
                {list.length > 0 &&
                    list.map((q: any) => {
                        const { _id } = q
                        return <QuestionCard key={_id} {...q} />
                    })}
            </div>
            <div className={styles.footer}>
                <div ref={containerRef}>{LoadMoreContentElem}</div>
            </div>
        </div>
    )
}

export default List
